'use client';

import {
  type ChangeEvent,
  type FormEvent,
  useEffect,
  useRef,
  useState,
} from 'react';
import { useMutation, useQuery } from '@tanstack/react-query';
import { queryPasswordPublicKey, updateUserPassword } from '@/services/api';
import type { TBody } from '@/types';
import type { IDifference, IUpdateUserPasswordBody, IUser } from '@/interfaces';
import diff from 'microdiff';
import { nanoid } from 'nanoid';
import type JSEncrypt from 'jsencrypt';
import useToast from '@/hooks/useToast';
import { getDiffData, getFilterData, isEmpty } from '@/lib/tool';

export default function UpdateUserPassword({ details }: { details: IUser }) {
  const jsEncryptRef = useRef<JSEncrypt | null>(null);
  const [form, setForm] = useState<{
    password?: string;
  }>({
    password: '',
  });
  const [differenceData, setDifferenceData] = useState<IDifference[]>([]);
  const [randomPassword, setRandomPassword] = useState('');
  const { show } = useToast();

  const queryPasswordPublicKeyQuery = useQuery(
    ['/key', '/public', '/password'],
    async () => {
      return (await queryPasswordPublicKey()) as string;
    },
    {
      enabled: false,
    },
  );

  const updateUserPasswordMutation = useMutation(
    async (variables: TBody<IUpdateUserPasswordBody>) => {
      await updateUserPassword(variables);
    },
  );

  useEffect(() => {
    if (details) {
      setForm({
        password: details.username ? '*********' : '',
      });
    }
  }, [details]);
  useEffect(() => {
    if (details) {
      const differences = diff(
        {
          password: details.username ? '*********' : '',
        },
        form,
      );
      setDifferenceData(differences);
    }
  }, [form, details]);

  async function getJsEncrypt(): Promise<JSEncrypt> {
    let jsEncrypt;
    if (jsEncryptRef.current) {
      jsEncrypt = jsEncryptRef.current;
    } else {
      const JSEncrypt = (await import('jsencrypt')).JSEncrypt;
      jsEncrypt = new JSEncrypt();
      jsEncryptRef.current = jsEncrypt;
    }
    return jsEncrypt;
  }

  async function getEncryptedPassword(password: string): Promise<string> {
    const jsEncrypt = await getJsEncrypt();
    const result = await queryPasswordPublicKeyQuery.refetch({
      throwOnError: true,
    });
    const publicKey = result.data;
    if (!publicKey) {
      throw '获取密码数据失败';
    }

    jsEncrypt.setPublicKey(publicKey);
    const encryptedData = jsEncrypt.encrypt(password);
    if (!encryptedData) {
      throw '加密密码数据失败';
    }

    return encryptedData;
  }

  function onChangeForm(e: ChangeEvent<HTMLInputElement>) {
    const name = e.target.name;
    const value = e.target.value;
    setForm({ ...form, [name]: value });
  }

  async function onClickSave(e: FormEvent<HTMLFormElement>) {
    try {
      e.preventDefault();
      e.stopPropagation();

      checkForm();
      const body = getFilterData(getDiffData(differenceData));
      if (isEmpty(body)) {
        show({
          type: 'SUCCESS',
          message: '保存完成',
        });
        return;
      }

      const password = await getEncryptedPassword(body.password);
      await updateUserPasswordMutation.mutateAsync({
        id: details.id,
        data: {
          password,
        },
      });

      clearData();
      show({
        type: 'SUCCESS',
        message: '保存完成',
      });
    } catch (e) {
      updateUserPasswordMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  function onClickGenerateRandomPassword() {
    const rPassword = nanoid();
    const password = rPassword.substring(0, Math.floor(rPassword.length / 2));
    setRandomPassword(password);
    setForm({ ...form, password });
  }

  function clearData() {
    setDifferenceData([]);
    setRandomPassword('');
    setForm({ ...form, password: '*********' });
  }

  function checkForm() {
    const { password } = form;
    if (!details.username) {
      throw '操作失败，无法修改当前密码';
    } else if (!password) {
      throw '密码不能为空';
    }
  }

  return (
    <div className="row">
      <div className="col">
        <form onSubmit={onClickSave} className="vstack gap-4">
          <div>
            <label className="form-label">
              <span className="text-danger">*</span>
              密码
              {randomPassword && (
                <span className="mx-2 text-muted">
                  (随机密码：{randomPassword}，请注意保存，只会显示一次)
                </span>
              )}
            </label>
            <div className="input-group">
              <input
                type="password"
                name="password"
                value={form.password}
                onChange={onChangeForm}
                className="form-control"
                autoComplete="password"
                placeholder="请输入密码，长度最小 6，最大 19"
              />
              <button
                onClick={onClickGenerateRandomPassword}
                className="btn btn-outline-secondary"
                type="button"
              >
                生成随机密码
              </button>
            </div>
          </div>

          <button
            type="submit"
            disabled={updateUserPasswordMutation.isLoading}
            className="btn btn-success w-25 my-4"
          >
            {updateUserPasswordMutation.isLoading && (
              <span
                className="spinner-border spinner-border-sm me-2"
                role="status"
                aria-hidden="true"
              ></span>
            )}
            更新
          </button>
        </form>
      </div>
    </div>
  );
}
